<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <div id="app">

        </div>
        <script src="vue.js"></script>
        <script>
        Vue.mixin2 = function(mixinOptions){
            //缓存老的_init方法
            const originInit = this.prototype._init;
            //重写老的init方法
            Vue.prototype._init = function(options){
                //在走老方法之前要先对options进行合并处理
                //合并的时候有三个来源
                //第1个来源是Vue上的默认选项
                //第2个来源mixin方法传递过来的mixinOptions
                //第3个来源new Vue的时候传递的选项
                options = mergeOptions(
                    Vue.options,mixinOptions,options
                );
                //最终还是要走的老的init方法
                originInit.call(this,options);
            }
        }
        function mergeOptions(defaultOptions,mixinOptions,newOptions){
            //先执行默认的合并规则 
            const options = Object.assign({},defaultOptions,mixinOptions,newOptions);
            //合并data数据
            options.data = Object.assign({},
            typeof defaultOptions.data==='function'?defaultOptions.data():defaultOptions.data,
            typeof mixinOptions.data==='function'?mixinOptions.data():mixinOptions.data,
            typeof newOptions.data==='function'?newOptions.data():newOptions.data,
            );
            //合并方法
            options.methods = Object.assign({},defaultOptions.methods,mixinOptions.methods,newOptions.methods);
            //合并计算属性
            options.computed = Object.assign({},defaultOptions.computed,mixinOptions.computed,newOptions.computed);
            //合并监听
            options.watch = Object.assign({},defaultOptions.watch,mixinOptions.watch,newOptions.watch);
            //合并方法
            options.methods = Object.assign({},defaultOptions.methods,mixinOptions.methods,newOptions.methods);
            //合并created钩子函数
            options.created = [defaultOptions.created,mixinOptions.created,newOptions.created].filter(Boolean);
            //合并mounted钩子函数
            options.mounted = [defaultOptions.mounted,mixinOptions.mounted,newOptions.mounted].filter(Boolean);
            return options;
        }
        const myMixin = {
            data:()=>({
                mixinData:'我是来自于mixin中的data'
            }),
            created(){
                console.log(`我是来自于mixin中的created`)
            },
            mounted(){
                console.log(`我是来自于mixin中的mounted`);
            },
            computed:{
                mixinComputed(){
                    return this.mixinData+'计算后得到的结果'
                }
            },
            watch:{
                mixinData(newVal,oldVal){
                    console.log(`mixinData的值从${oldVal}变成了${newVal}`)
                }
            },
            methods:{
                mixinMethod(){
                    console.log('mixinMethod')
                }
            }
        }
        Vue.mixin2(myMixin);
        var vm = new Vue({
            el:'#app',
            data:{
                localData:'我是来自于local中的data'
            },
            created(){
                console.log(`我是来自于local中的created`)
            },
            mounted(){
                console.log(`我是来自于local中的mounted`)
            },
            computed:{
                localComputed(){
                    return this.localData+'计算后得到的结果'
                }
            },
            watch:{
                localData(newVal,oldVal){
                    console.log(`localData从旧值${oldVal}变成了新值${newVal}`)
                }
            },
            methods:{
                localMethod(){
                    console.log('localMethod')
                }
            }
        });
    </script>
    </body>
</html>